package com.android_map_app.activities;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.android_map_app.R;
import com.android_map_app.data.User;
import com.android_map_app.data.UserData;
import com.android_map_app.services.UpdateService;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

public class MapViewActivity extends MapActivity {

	private static final String TAG = MapViewActivity.class.getSimpleName();
	private final int MINZOOM = 14;
	private LinkedList<GeoPoint> points;
	Context context;
	MapView mapView;
	List<Overlay> mapOverlays;
	Drawable userDrawable;
	Drawable otherDrawable;
	MapController mc;
	MapUpdateReceiver receiver;
	MapApplication mapApplication;
	GeoPoint prevCenterPoint = new GeoPoint(0, 0);
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.map);
		context = getApplicationContext();
		mapApplication = (MapApplication) getApplication();
		points = new LinkedList<GeoPoint>();
		
		mapView = (MapView) findViewById(R.id.mapview);
		mapView.setBuiltInZoomControls(true);
		mapView.displayZoomControls(true);
		mapOverlays = mapView.getOverlays();
		mc = mapView.getController();

		userDrawable = this.getResources().getDrawable(R.drawable.ic_map_marker_red);
		otherDrawable = this.getResources().getDrawable(R.drawable.ic_map_marker_blue);
		
		startService(new Intent(this, UpdateService.class)); //start update service
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		if (receiver == null) {
			receiver = new MapUpdateReceiver();
		}
		registerReceiver(receiver, new IntentFilter(UpdateService.ACTION_NEW_COORDINATES));
	}

	@Override
	protected void onPause() {
		super.onPause();
		unregisterReceiver(receiver);
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.map_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.itemToggleService:
			if (mapApplication.isServiceRunning()) {
				stopService(new Intent(this, UpdateService.class));
			} else {
				startService(new Intent(this, UpdateService.class));
			}
			break;
		}
		return true;
	}
	
	@Override
	public boolean onMenuOpened(int featureId, Menu menu) {
		MenuItem toggleItem = menu.findItem(R.id.itemToggleService);
		if (mapApplication.isServiceRunning()) {
			toggleItem.setTitle(R.string.titleServiceStop);
			toggleItem.setIcon(android.R.drawable.ic_media_pause);
		} else {
			toggleItem.setTitle(R.string.titleServiceStart);
			toggleItem.setIcon(android.R.drawable.ic_media_play);
		}
		return true;
	}
	
	private void updateOverlays() {
		try {
			int minLatitude = Integer.MAX_VALUE;
			int maxLatitude = Integer.MIN_VALUE;
			int minLongitude = Integer.MAX_VALUE;
			int maxLongitude = Integer.MIN_VALUE;
			
			mapOverlays.clear();
			points.clear();
			User user = UserData.getInstance().getUser();
			Location location = user.getLocation();
			LinkedList<User> users = UserData.getInstance().getActiveGroupMembers();
			//======= user marker =======
			MapItemizedOverlay itemizedOverlay = new MapItemizedOverlay(otherDrawable);
			GeoPoint point;
			OverlayItem overlayitem;
			if (location != null) {
				point = new GeoPoint((int) (location.getLatitude() * 1E6), (int) (location.getLongitude() * 1E6));
				overlayitem = new OverlayItem(point, user.getUsername(), "");
				itemizedOverlay.addOverlay(overlayitem, userDrawable);
				points.add(point);
			}
			
			//========= other users markers ========
			if (users != null) {
				for (User u : users) {
					location = u.getLocation();
					point = new GeoPoint((int) (location.getLatitude() * 1E6), (int) (location.getLongitude() * 1E6));
					overlayitem = new OverlayItem(point, u.getUsername(), "");
					itemizedOverlay.addOverlay(overlayitem, otherDrawable);
					points.add(point);
				}
			} else {
				Log.d(TAG, "no other users");
			}
			mapOverlays.add(itemizedOverlay);
			
			for (GeoPoint item : points) {
				int lat = item.getLatitudeE6();
				int lon = item.getLongitudeE6();
				
				maxLatitude = Math.max(lat, maxLatitude);
				minLatitude = Math.min(lat, minLatitude);
				maxLongitude = Math.max(lon, maxLongitude);
				minLongitude = Math.min(lon, minLongitude);
			}
			GeoPoint curCenterPoint = new GeoPoint((maxLatitude + minLatitude) / 2,
					(maxLongitude + minLongitude) / 2);
			if (!curCenterPoint.equals(prevCenterPoint)) {
				prevCenterPoint = curCenterPoint;
				if (points.size() > 1) {
					mc.zoomToSpan(Math.abs(maxLatitude - minLatitude), Math.abs(maxLongitude - minLongitude));
				} else {
					mc.zoomToSpan(maxLatitude, maxLongitude);
				}
				mc.animateTo(new GeoPoint( 
						(maxLatitude + minLatitude)/2, 
						(maxLongitude + minLongitude)/2 )); 
			}
			mapView.invalidate();
		} catch (Exception e) {
			Log.d(TAG, "fail updating overlays - " + e.getMessage());
			Toast.makeText(context, R.string.errorOverlayUpdate, Toast.LENGTH_LONG).show();
			stopService(new Intent(getApplicationContext(), UpdateService.class));
			startActivity(new Intent(getApplicationContext(), MainActivity.class));
		}
	}
	
	private class MapItemizedOverlay extends ItemizedOverlay<OverlayItem> {
		
		private ArrayList<OverlayItem> mOverlays;

		public MapItemizedOverlay(Drawable defaultMarker) {
			super(boundCenterBottom(defaultMarker));
			mOverlays = new ArrayList<OverlayItem>();
			populate();
		}

		public void addOverlay(OverlayItem overlay) {
		    mOverlays.add(overlay);
		    populate();
		}
		
		public void addOverlay(OverlayItem overlay, Drawable marker) {
			overlay.setMarker(boundCenterBottom(marker));
		    mOverlays.add(overlay);
		    populate();
		}
		
		@Override
		protected OverlayItem createItem(int i) {
			return mOverlays.get(i);
		}

		@Override
		public boolean onTap(int i) {
			GeoPoint  gpoint = mOverlays.get(i).getPoint();
            double lat = gpoint.getLatitudeE6()/1e6;
            double lon = gpoint.getLongitudeE6()/1e6;
            String toast = "User: "+mOverlays.get(i).getTitle()
            		+ "\nCoordinates: \nLat = " + lat + "\nLon = " + lon + "";
            Toast.makeText(context, toast, Toast.LENGTH_SHORT).show();
            return(true);
		}

		@Override
		public int size() {
			return mOverlays.size();
		}
		
	}
	
	class MapUpdateReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			updateOverlays();
		}
		
	}
}
